const axios = require('axios')
const convert = require('xml-js')
const log4js = require("log4js")
const QRCode = require('qrcode')
const getRawBody = require('raw-body')
const contentType = require('content-type')

// log4js配置，level决定什么级别的log会被打印
log4js.configure({
  appenders: { cheese: { type: "file", filename: "cheese.log" } },
  categories: { default: { appenders: ["cheese"], level: "error" } }
})
var logger = log4js.getLogger()
logger.level = "debug"

// 调用统一下单接口的参数：appid,mch_id,notify_url,trade_type。
// unifiedorderApi：统一下单接口，key：为商户平台设置的密钥key
// 都是常量
const {
  unifiedorderApi,
  appid,
  mch_id,
  notify_url,
  trade_type,
} = require('../config')

const { genNonceStr, genSign } = require('../utils')

const qrcode = async (ctx, next) => {
  const { body, out_trade_no } = ctx.request.body
  const nonce_str = genNonceStr()

  // total_fee: 订单的总价，一般由传给接口，单位是分，最小值是1分钱
  const total_fee = 1

  // _prepay 用来生成sign
  const _prepay = {
    body,
    out_trade_no,
    nonce_str,
    total_fee,
    appid,
    mch_id,
    notify_url,
    trade_type
  }

  const signValue = genSign(_prepay)
  
  // 验证调用返回或微信主动通知签名时，传送的sign参数不参与签名，将生成的签名与该sign值作校验。
  const prepay = {
    ..._prepay,
    sign: signValue
  }

  // 注意，传给统一下单接口的参数必须是XML
  const xml = convert.js2xml({
    xml: {
      ...prepay
    }
  }, {
    compact: true
  })

  // 调用统一下单接口
  let result = await axios.post(unifiedorderApi, xml)

  // 得到 code_url
  let data = convert.xml2js(result.data, {
    compact: true,
    cdataKey: 'value'
  }).xml

  let resultObj = Object.keys(data).reduce((obj, key) => {
    obj[key] = data[key]['value']
    // logger.debug(obj)
    return obj
  }, {})

  if (resultObj.result_code === 'FAIL') {
    ctx.body = resultObj.err_code_des
  } else {
    let code_url = resultObj.code_url
    const generateQR = async text => {
      try {
        return await QRCode.toDataURL(text)
      } catch (err) {
        console.error(err)
      }
    }
  
    let qrcode = await generateQR(code_url)
  
    // 根据生成qrcode(base64), 渲染模板
    await ctx.render('qrcode', {
      qrcode
    })
  }

}

const notify = async (ctx, next) => {
  let result = await getRawBody(ctx.req, {
    length: ctx.req.headers['content-length'],
    limit: '1mb',
    encoding: contentType.parse(ctx.req).parameters.charset
  })

  let notifyResult = convert.xml2js(result.toString(), {
    compact: true,
    cdataKey: 'value',
    textKey: 'value'
  }).xml
  logger.debug(notifyResult)

  let resultObj = Object.keys(notifyResult).reduce((obj, key) => {
    obj[key] = notifyResult[key]['value']
    return obj
  }, {})

  let sign = resultObj.sign
  delete resultObj.sign

  const signValue = genSign(resultObj)

  ctx.set('Content-type', 'text/plain')
  if (signValue === sign) {
    ctx.body = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'
  } else {
    ctx.body = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>'
  }
}

module.exports = {
  qrcode,
  notify
}